import colorsys
import os
import platform
import random
import time

import cv2
import pdfplumber
import numpy as np

import random_color
from find_blank import get_contours

print("Version of opencv:", cv2.__version__)

def distance(a, b):
    return np.linalg.norm(a-b)


# 选取密集关键点
def find_keypoints(pdf_path: str, pdf_pageNumber: int, image_resolution=256):
    kps = []
    image_save_folder = "images"
    sysstr = platform.system()
    if(sysstr =="Windows"):
        pdf_filename_without_ext = ".".join(pdf_path.split("\\")[-1].split(".")[:-1])
    elif(sysstr == "Linux"):
        pdf_filename_without_ext = ".".join(pdf_path.split("/")[-1].split(".")[:-1])
    else:
        print("Not Expect System!")
    if pdf_filename_without_ext:
        image_name = pdf_filename_without_ext + "_Page" + str(pdf_pageNumber) + ".png"
        image_path = os.path.join(image_save_folder, image_name)
        try:
            with pdfplumber.open(pdf_path) as pdf:
                try:
                    page = pdf.pages[pdf_pageNumber]
                except IndexError:
                    print("Please check PDF page number.")
                image = page.to_image(resolution=image_resolution)
                scale = float(image_resolution/72)
                image.save(image_path, format="png")

                for char in page.chars:
                    radius = int(float(char["height"])/2)
                    x = int(scale * (float(char["x0"]) + float(char["width"])/2))
                    y = int(scale * (float(char["top"]) + float(char["height"])/2))
                    kps.append(cv2.KeyPoint(x, y, radius * 2))

        except FileNotFoundError:
            print("Please check PDF file path.")
        return kps, image_path


def equal(a, b, T=180):
    if np.linalg.norm(a-b) <= T:
        return True
    else:
        return False


def find_lckeypoints(s1, s2): 
	# 生成字符串长度加1的0矩阵，m用来保存对应位置匹配的结果
    m = [ [ 0 for x in range(len(s2)+1) ] for y in range(len(s1)+1) ] 
    # d用来记录转移方向
    d = [ [ None for x in range(len(s2)+1) ] for y in range(len(s1)+1) ] 
 
    for p1 in range(len(s1)): 
        for p2 in range(len(s2)):
            #字符匹配成功，则该位置的值为左上方的值加1
            if equal(s1[p1],s2[p2]):
                # print("Check distance of des1[{}] & des2[{}]".format(p1, p2))
                # print("Calculate distance of des1[{}] & des2[{}]".format(p1, p2))
                m[p1+1][p2+1] = m[p1][p2]+1
                d[p1+1][p2+1] = 'ok'
            #左值大于上值，则该位置的值为左值，并标记回溯时的方向
            elif m[p1+1][p2] > m[p1][p2+1]: 
                m[p1+1][p2+1] = m[p1+1][p2]
                d[p1+1][p2+1] = 'left'
            #上值大于左值，则该位置的值为上值，并标记方向up
            else: 
                m[p1+1][p2+1] = m[p1][p2+1]
                d[p1+1][p2+1] = 'up'
    (p1, p2) = (len(s1), len(s2)) 

    s = []
    comman_index1 = []
    comman_index2 = []
    while m[p1][p2]: #不为None时
        c = d[p1][p2]
        if c == 'ok': #匹配成功，插入该字符，并向左上角找下一个
            s.append(s1[p1-1])
            comman_index1.append(p1-1)
            comman_index2.append(p2-1)
            p1-=1
            p2-=1 
        if c =='left':  #根据标记，向左找下一个
            p2 -= 1
        if c == 'up':   #根据标记，向上找下一个
            p1 -= 1
    s.reverse()
    comman_index1.reverse()
    comman_index2.reverse()
    return s, comman_index1, comman_index2


def draw_keypoints(image, good_kps):
    for good_kp in good_kps:
        cv2.circle(image, 
                   (int(good_kp.pt[0]), int(good_kp.pt[1])),
                   radius=3*6,
                   color=[0, 0, 255],
                   thickness=4)
    return image


if __name__ == "__main__":

    test_case = {
        "original": 0,
        "add": 1,
        "delete": 2,
        "modify": 3,
        "add_delete": 4,
        "delete_modify": 5,
        "add_modify": 6
    }

    COMPARE = "add_delete"
    
    RESO = 512 # PDF文档转出图像的分辨率,单位:像素/英寸

    # 要对比的两份PDF文档路径及页码
    pdf1 = "documents/test.pdf"
    page_number1 = test_case["original"]
    pdf2 = "documents/test.pdf"
    page_number2 = test_case[COMPARE]

    start_time = time.time()
    # 设置sift算子
    sift = cv2.xfeatures2d.SIFT_create()

    # 获取每个字符对应的特征点
    kps1, image_path1 = find_keypoints(pdf_path=pdf1, 
                                       pdf_pageNumber=page_number1, 
                                       image_resolution=RESO)

    kps2, image_path2 = find_keypoints(pdf_path=pdf2, 
                                       pdf_pageNumber=page_number2, 
                                       image_resolution=RESO)

    image1 = cv2.imread(image_path1)
    image2 = cv2.imread(image_path2)

    image1_copy = image1.copy()
    image2_copy = image2.copy()

    # 计算密集描述符
    _, des1 = sift.compute(image1, kps1)
    _, des2 = sift.compute(image2, kps2)

    # print("Number of key points: Image1:{}, Image2:{}".format(len(kps1), len(kps2)))
        
    # 画出关键点
    # image3 = cv2.drawKeypoints(image1, kps1, None, color=[0, 0, 255])
    # image4 = cv2.drawKeypoints(image2, kps2, None, color=[255, 0, 0])
    # cv2.imwrite("Keypoints.png", np.hstack([image3, image4]))

    _, kp1_index, kp2_index = find_lckeypoints(des1, des2)
    
    good_kps1 = []
    good_kps2 = []
    for i in kp1_index:
        good_kps1.append(kps1[i])
    for i in kp2_index:
        good_kps2.append(kps2[i])
    
    # print("Length of good kps1:{} & good kps2:{}".format(len(good_kps1), len(good_kps2)))
    end_time = time.time()
    image5 = draw_keypoints(image1_copy, good_kps1)
    image6 = draw_keypoints(image2_copy, good_kps2)
    cv2.imwrite(COMPARE + ".png", np.hstack([image5, image6]))
    print("Total time:{}".format(end_time-start_time))